package com.lh.filter;

import com.google.gson.Gson;
import com.lh.model.ReturnModel;
import com.lh.model.SessionAndOpenModel;
import com.lh.myclass.*;
import com.lh.myenum.EnumClass;
import com.lh.service.IpService;
import com.lh.unit.CheckAccessTokenClass;
import com.lh.unit.RedisOperator;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.FORWARD_TO_KEY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY;

/**
 * @author 梁昊
 * @date 2018/10/20
 * @function 身份认证过滤器
 * @editLog 过滤IP黑名单和白名单，判断是BS还是CS，判断是否需要身份验证
 */
public class AccessTokenFilter extends ZuulFilter {
    @Autowired
    Gson gson;
    @Autowired
    IpService ipService;
    @Autowired
    CheckAccessTokenClass checkAccessTokenClass;
    @Autowired
    RedisOperator redisOperator;

    public AccessTokenFilter() {
        super();
        iniFilter();
    }

    private final String TokenName = "accessToken";
    private final String UseId = "useId";
    private final String UseType = "useType";
    private final String ClientType = "clientType";
    private final String SystemId = "systemId";
    private final int nStatusCode = 401;

    private final String AppId = "appId";
    private final String Code = "code";
    private final String SessionKey = "sessionKey";

    private MyWhiteNameList myWhiteNameList;
    private MyBlackNameList myBlackNameList;

    public void iniFilter() {
        myBlackNameList = new MyBlackNameList();
        myWhiteNameList = new MyWhiteNameList();
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        return !ctx.containsKey(FORWARD_TO_KEY)
                && !ctx.containsKey(SERVICE_ID_KEY);
    }

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public Object run() {
        Logger logger = Logger.getLogger("chapter07");
        ReturnModel returnModel = new ReturnModel();
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        HttpServletResponse response = ctx.getResponse();

        String useIp = request.getRemoteAddr();

        if (myBlackNameList.isAllow(useIp)) {
            returnModel.setOkSign(true);
            myWhiteNameList = new MyWhiteNameList();
            String getRequestURI = request.getRequestURI();
            IsCheckWhitePath isCheckWhitePath = new IsCheckWhitePath();

            if (isCheckWhitePath.isCheckWhite(getRequestURI)) {
                returnModel.setOkSign(myWhiteNameList.isAllow(useIp));
                if (!returnModel.isOkSign()) {
                    returnModel.setMessage(String.format("您的IP(%s)未在白名单中，不允许访问！", useIp));
                }
            }

            if (returnModel.isOkSign()) {
                OperateTypeClass operateTypeClass = new OperateTypeClass();
                EnumClass.CheckIdentityEnum checkIdentityEnum = operateTypeClass.GetOperateType(getRequestURI);
                returnModel.setOkSign(false);
                switch (checkIdentityEnum) {
                    case IS_CS:
                    case IS_ANDROID: {
                        try {
                            final ServletInputStream inputStream = request.getInputStream();
                            if (inputStream != null) {
                                byte[] readByte = new byte[1024];
                                inputStream.read(readByte);
                                if (readByte != null && readByte.length > 0){
                                    String body = new String(readByte, Charset.forName("utf-8"));
                                    System.out.println("body:" + body);
                                }

                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
//                        final InputStream responseDataStream = ctx.getResponseDataStream();
//                        if (responseDataStream != null) {
//                            byte[] readByte = new byte[1024];
//                            try {
//                                responseDataStream.read(readByte);
//                                if (readByte != null && readByte.length > 0) {
//                                    String body = new String(readByte, Charset.forName("utf-8"));
//                                    System.out.println("body:" + body);
//                                }
//                            } catch (IOException e) {
//                                e.printStackTrace();
//                            }
//                        }
                    }
                    case IS_IOS: {
//                        String accessToken = request.getParameter(TokenName);
//                        String useId = request.getParameter(UseId);
//                        String useType = request.getParameter(UseType);
//                        String clientType = request.getParameter(ClientType);
//                        String systemId = request.getParameter(SystemId);
//                        if ((accessToken != null)
//                                && (useId != null)
//                                && (useType != null)
//                                && (clientType != null)
//                                && (systemId != null)) {
//                            returnModel.setOkSign(checkAccessTokenClass.checkUseToken(systemId
//                                    , clientType
//                                    , useId
//                                    , useType
//                                    , accessToken));
//                            if (!returnModel.isOkSign())
//                                returnModel.setMessage("兄弟，被拦截了，你的accessToken无效！");
//                        } else
//                            returnModel.setMessage(String.format("兄弟，被拦截了，请检查这些参数是否传入：%s,%s,%s,%s,%s。"
//                                    , TokenName
//                                    , UseId
//                                    , UseType
//                                    , ClientType
//                                    , SystemId)
//                            );
                        returnModel.setOkSign(true);
                    }
                    break;
                    case IS_BS: {
                        Cookie[] cookies = request.getCookies();
                        if (cookies != null) {
                            logger.info("cookies:" + cookies.length);
                        }
                        returnModel.setOkSign(cookies == null ? false : true);
                        if (returnModel.isOkSign()) {
                            String useId = null;
                            String accessToken = null;
                            String useType = null;
                            String clientType = null;
                            String systemId = null;
                            for (Cookie row : cookies
                            ) {
                                if (row.getName().equals(TokenName)) {
                                    accessToken = row.getValue();
                                }
                                if (row.getName().equals(UseId)) {
                                    useId = row.getValue();
                                }
                                if (row.getName().equals(UseType)) {
                                    useType = row.getValue();
                                }
                                if (row.getName().equals(ClientType)) {
                                    clientType = row.getValue();
                                }
                                if (row.getName().equals(SystemId)) {
                                    systemId = row.getValue();
                                }
                            }
                            if (returnModel.isOkSign()
                                    && accessToken != null
                                    && useId != null
                                    && useType != null
                                    && clientType != null
                                    && systemId != null) {
                                returnModel.setOkSign(checkAccessTokenClass.checkUseToken(systemId
                                        , clientType
                                        , useId
                                        , useType
                                        , accessToken));
                                if (returnModel.isOkSign()) {
                                    request.getParameterMap();
                                    Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams();
                                    if (requestQueryParams != null) {
                                        addRequestQueryParams(UseId, useId, requestQueryParams);
                                        addRequestQueryParams(UseType, useType, requestQueryParams);
                                        addRequestQueryParams(ClientType, clientType, requestQueryParams);
                                        addRequestQueryParams(SystemId, systemId, requestQueryParams);
                                    } else {
                                        requestQueryParams = new HashMap<>();
                                        List<String> listUseId = new ArrayList<>();
                                        listUseId.add(useId);
                                        List<String> listUseType = new ArrayList<>();
                                        listUseType.add(useType);
                                        List<String> listClientType = new ArrayList<>();
                                        listClientType.add(clientType);
                                        List<String> listSystemId = new ArrayList<>();
                                        listSystemId.add(systemId);
                                        requestQueryParams.put(UseId, listUseId);
                                        requestQueryParams.put(UseType, listUseType);
                                        requestQueryParams.put(ClientType, listClientType);
                                        requestQueryParams.put(SystemId, listSystemId);
                                    }
                                    ctx.setRequestQueryParams(requestQueryParams);
                                }
                            }
                        }
                        if (!returnModel.isOkSign()) {
                            returnModel.setMessage("未得到Cookies，你被拦截了，兄弟！");
                            break;
                        }
                    }
                    case IS_NO: {
                        String myOrigin = request.getHeader("origin");
                        logger.info("NO:" + myOrigin);
                        returnModel.setOkSign(redisOperator.getOriginValid(myOrigin));
                        if (returnModel.isOkSign()) {
                            response.setHeader("Access-Control-Allow-Origin", myOrigin);
                            response.setHeader("Access-Control-Allow-Method", "OPTIONS, TRACE, GET, HEAD, POST, PUT");
                            response.setHeader("Access-Control-Allow-Credentials", "true");
                            response.setContentType("application/json;text/html;charset=UTF-8");
                            response.setCharacterEncoding("UTF-8");
                        } else
                            returnModel.setMessage("origin为空，或是不允许的origin，你被拦截了，兄弟！");
                    }
                    break;
                    case IS_WEIXIN_PUBLIC:
                    case IS_WEIXIN_SMALLPROGRAME: {
                        Object appId = request.getParameter(AppId);
                        Object code = request.getParameter(Code);
                        Object sessionKey = request.getParameter(SessionKey);
                        if ((appId != null) && (code != null) && (sessionKey != null)) {
                            String sessionKeyAndOpenIdModel = redisOperator.getSessionKeyAndOpenId(
                                    appId.toString()
                                    , code.toString());
                            if (sessionKeyAndOpenIdModel != null) {
                                final SessionAndOpenModel sessionAndOpenModel = gson.fromJson(sessionKeyAndOpenIdModel, SessionAndOpenModel.class);
                                final String replace = sessionAndOpenModel.getSessionKey().replace('+', ' ');
                                if (replace.equals(sessionKey)) {
                                    returnModel.setOkSign(true);
                                } else
                                    returnModel.setMessage("兄弟，被拦截了，SessionKey不对！");
                            }
                        } else
                            returnModel.setMessage(String.format("兄弟，被拦截了，请检查这些参数是否传入：%s,%s,%s。"
                                    , "appId"
                                    , "code"
                                    , "sessionKey")
                            );
                        break;
                    }
                    case IS_LOCALREMOTE:
                    case IS_OTHER:
                        returnModel.setOkSign(true);
                        break;
                    default:
                        returnModel.setOkSign(true);
                        break;
                }
            }
        } else {
            returnModel.setMessage(String.format("您的IP(%s)已进入黑名单，不允许访问！", useIp));
        }

        if (returnModel.isOkSign()) {
//            if (!useIp.equals("192.168.1.123")) {
////                RibbonFilterContextHolder.getCurrentContext().add("version", "1");
////            } else {
////                RibbonFilterContextHolder.getCurrentContext().add("version", "2");
////            }
        } else {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(nStatusCode);
            ctx.getResponse().setContentType("text/html;charset=UTF-8");
            ctx.setResponseBody(returnModel.getMessage());
        }
        return null;
    }

    private void addRequestQueryParams(String keyName, String keyValue, Map<String, List<String>> requestQueryParams) {
        if (!requestQueryParams.containsKey(keyName)) {
            List<String> list = new ArrayList<>();
            list.add(keyValue);
            requestQueryParams.put(keyName, list);
        }
    }

}
